﻿Imports System
Imports System.Collections
Imports System.Reflection
Imports System.Workflow.ComponentModel

Namespace System.Workflow.ComponentModel.Compiler
    Public Class Validator
        ' Methods
        Protected Function GetFullPropertyName(ByVal manager As ValidationManager) As String
            If (manager Is Nothing) Then
                Throw New ArgumentNullException("manager")
            End If
            Dim propertyName As String = String.Empty
            Dim i As Integer = 0
            Do While (Not manager.Context.Item(i) Is Nothing)
                If TypeOf manager.Context.Item(i) Is PropertyValidationContext Then
                    Dim context As PropertyValidationContext = [TryCast](manager.Context.Item(i),PropertyValidationContext)
                    If (context.PropertyName = String.Empty) Then
                        propertyName = String.Empty
                    ElseIf (propertyName = String.Empty) Then
                        propertyName = context.PropertyName
                    Else
                        propertyName = (context.PropertyName & "." & propertyName)
                    End If
                End If
                i += 1
            Loop
            Return propertyName
        End Function

        Public Overridable Function Validate(ByVal manager As ValidationManager, ByVal obj As Object) As ValidationErrorCollection
            If (manager Is Nothing) Then
                Throw New ArgumentNullException("manager")
            End If
            If (obj Is Nothing) Then
                Throw New ArgumentNullException("obj")
            End If
            Return New ValidationErrorCollection
        End Function

        Public Overridable Function ValidateActivityChange(ByVal activity As Activity, ByVal action As ActivityChangeAction) As ValidationError
            If (activity Is Nothing) Then
                Throw New ArgumentNullException("activity")
            End If
            If (action Is Nothing) Then
                Throw New ArgumentNullException("action")
            End If
            Return Nothing
        End Function

        Public Overridable Function ValidateProperties(ByVal manager As ValidationManager, ByVal obj As Object) As ValidationErrorCollection
            If (manager Is Nothing) Then
                Throw New ArgumentNullException("manager")
            End If
            If (obj Is Nothing) Then
                Throw New ArgumentNullException("obj")
            End If
            Dim errors As New ValidationErrorCollection
            Dim activity As Activity = [TryCast](manager.Context.Item(GetType(Activity)),Activity)
            Dim walker As New Walker(True)
            AddHandler walker.FoundProperty, Function (ByVal w As Walker, ByVal args As WalkerEventArgs) 
                If ((Not args.CurrentProperty Is Nothing) AndAlso (DependencyProperty.FromName(args.CurrentProperty.Name, args.CurrentProperty.DeclaringType) Is Nothing)) Then
                    Dim customAttributes As Object() = args.CurrentProperty.GetCustomAttributes(GetType(ValidationOptionAttribute), True)
                    If (If((customAttributes.Length > 0), DirectCast(customAttributes(0), ValidationOptionAttribute).ValidationOption, ValidationOption.Optional) <> ValidationOption.None) Then
                        errors.AddRange(Me.ValidateProperty(args.CurrentProperty, args.CurrentPropertyOwner, args.CurrentValue, manager))
                        args.Action = WalkerAction.Skip
                    End If
                End If
            End Function
            walker.WalkProperties(activity, obj)
            Return errors
        End Function

        Protected Friend Function ValidateProperty(ByVal propertyInfo As PropertyInfo, ByVal propertyOwner As Object, ByVal propertyValue As Object, ByVal manager As ValidationManager) As ValidationErrorCollection
            Dim errors As New ValidationErrorCollection
            Dim customAttributes As Object() = propertyInfo.GetCustomAttributes(GetType(ValidationOptionAttribute), True)
            If (customAttributes.Length > 0) Then
                Dim validationOption As ValidationOption = DirectCast(customAttributes(0), ValidationOptionAttribute).ValidationOption
            End If
            Dim context As New PropertyValidationContext(propertyOwner, propertyInfo, propertyInfo.Name)
            manager.Context.Push(context)
            Try 
                If (propertyValue Is Nothing) Then
                    Return errors
                End If
                errors.AddRange(ValidationHelpers.ValidateObject(manager, propertyValue))
                If Not TypeOf propertyValue Is IList Then
                    Return errors
                End If
                Dim context2 As New PropertyValidationContext(propertyValue, Nothing, "")
                manager.Context.Push(context2)
                Try 
                    Dim obj2 As Object
                    For Each obj2 In DirectCast(propertyValue, IList)
                        errors.AddRange(ValidationHelpers.ValidateObject(manager, obj2))
                    Next
                    Return errors
                Finally
                    manager.Context.Pop
                End Try
            Finally
                manager.Context.Pop
            End Try
            Return errors
        End Function

    End Class
End Namespace

